package com.ideaaedi.springcloud.jd.commonspring.mybatisplus;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ideaaedi.springcloud.jd.commonds.constant.BaseConstant;
import com.ideaaedi.springcloud.jd.commonds.entity.EntityPackageLocator;
import com.ideaaedi.springcloud.jd.commonds.util.ClassUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * mp相关数据持有器
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2021.0.5.B
 */
@Slf4j
@Configuration
public class MybatisPlusInfoHolder implements ApplicationRunner {
    
    @Resource
    private ApplicationContext applicationContext;
    
    /** poClass - service映射 */
    @Getter
    @SuppressWarnings("rawtypes")
    private final Map<Class, IService> clazzServiceMapping = new ConcurrentHashMap<>(64);
    
    /** poClass - Constructor映射 */
    @Getter
    @SuppressWarnings("rawtypes")
    private final Map<Class, Constructor> clazzConstructorMapping = new ConcurrentHashMap<>(128);
    
    /** 记录所有租户表 */
    @Getter
    private Set<String> tenantTables = null;
    
    /**
     * 初始化租户表
     */
    @PostConstruct
    public void initTenantTables() {
        tenantTables = new HashSet<>();
        List<String> poClassLongNameList = new ArrayList<>(64);
        poClassLongNameList.addAll(
                ClassUtil.getClazzName(new EntityPackageLocator().locate(), true)
        );
        try {
            for (String poClassLongName : poClassLongNameList) {
                Class<?> clazz = Class.forName(poClassLongName);
                TableName tableNameAnno = clazz.getDeclaredAnnotation(TableName.class);
                if (tableNameAnno == null) {
                    continue;
                }
                String tableName = tableNameAnno.value();
                boolean existTenantColumn = true;
                try {
                    clazz.getDeclaredField(BaseConstant.TENANT_PROPERTY_NAME);
                } catch (NoSuchFieldException e) {
                    existTenantColumn = false;
                }
                if (existTenantColumn) {
                    if (tableName.contains(BaseConstant.MYSQL_ANTI_ESCAPE)) {
                        tableName = tableName.replace(BaseConstant.MYSQL_ANTI_ESCAPE, BaseConstant.EMPTY);
                    }
                    tenantTables.add(tableName);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        log.info("tenantTables -> {}", JSON.toJSONString(tenantTables));
    }
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        //noinspection rawtypes
        Map<String, ServiceImplExt> iserviceMap = applicationContext.getBeansOfType(ServiceImplExt.class);
        // 采集表对应的模型类与service的映射关系
        if (!CollectionUtils.isEmpty(iserviceMap)) {
            iserviceMap.values().forEach(x -> {
                Class<T> entityClass = x.getEntityClass();
                clazzServiceMapping.put(entityClass, x);
                //noinspection unchecked
                clazzConstructorMapping.put(entityClass, (Constructor<T>)entityClass.getDeclaredConstructors()[0]);
            });
        }
    }
}